今天以實例說明何以類別要有私有屬性。實務上私有屬性的機制,對類別究竟有甚麼「貢獻」。
物件.屬性
來存取物件本身的屬性,用起來很方便。class Tree(): # class
def __init__(self, breed: str, age: int, height: int):
self.breed = breed # public attribute
self.age = age # public attribute
self.height = height # public attribute
trees = [] # list of trees
trees.append(Tree('cedar', 3_250, 33)) # 造一棵雪松。
trees.append(Tree('oak', 285, 19)) # 造一棵橡樹。
trees.append(Tree('bristlecone pine', 4_854, 10)) # 造一棵刺果松。
# 每一棵tree(不是Tree,也不是trees)都是一個object(or instance)。
for tree in trees:
print(f'{tree.breed=:20}{tree.age=:<10,}{tree.height=}')
輸出:camphor = Tree('camphor', 600, 27) # 再造一棵樟樹。
print(f'\n{camphor.breed=:12}{camphor.age=:<12,}{camphor.height=}')
camphor.age = 300_000 # 樹妖姥姥
camphor.height = -50 # 樹高為負要表達甚麼概念?
print(f'{camphor.breed=:12}{camphor.age=:<12,}{camphor.height=}')
執行後資料真的改掉了:class Tree():
def __init__(self, breed: str, age: int, height: int):
self.__breed = breed # private attribute
self.__age = age # private attribute
self.__height = height # private attribute
class Tree():
def __init__(self, breed: str, age: int, height: int):
self.__breed = breed # private attribute
self.__age = age # private attribute
self.__height = height # private attribute
def get_breed(self) -> str: # public getter for breed
return self.__breed
def set_breed(self, breed: str): # public setter for breed
self.__breed = breed
def get_age(self) -> int: # public getter for age
return self.__age
def set_age(self, age: int): # public setter for age
self.__age = age
def get_height(self) -> int: # public getter for height
return self.__height
def set_height(self, height: int): # public setter for height
self.__height = height
camphor = Tree('camphor', 600, 27) # 造一棵樟樹。
print(f'breed: {camphor.get_breed():<12}age: {camphor.get_age():<12,}height: {camphor.get_height():<12}')
camphor.set_breed('cabbage') # 透過公開的setter來更改私有屬性breed的值
camphor.set_age(999_999) # 透過公開的setter來更改私有屬性age的值
camphor.set_height(-9) # 透過公開的setter來更改私有屬性height的值
print(f'breed: {camphor.get_breed():<12}age: {camphor.get_age():<12,}height: {camphor.get_height():<12}')
輸出:class Tree():
def __init__(self, breed, age, height):
self.__breed = breed
self.__age = age
self.__height = height
def get_age(self) -> int: # public getter for age
return self.__age
def set_age(self, age: int): # public setter for age
age_ranges = {'camphor': [0, 800], 'oak': [0, 300]}
if age < age_ranges[self.__breed][0] or age > age_ranges[self.__breed][1]:
raise Exception('樹齡數字不合理。')
else: # 放行
self.__age = age
camphor = Tree("camphor", 50, 37)
print(f"before set_age(): {camphor.get_age()=}")
try:
camphor.set_age(3_000) # 傳入超出合理範圍的值。
except Exception as e:
print(e)
print(f"after set_age() : {camphor.get_age()=}")
結果是:camphor = Tree("camphor", 50, 37)
print(f"before set_age(): {camphor.get_age()=}")
try:
camphor.set_age(145) # 這次傳入在合理範圍以內的值給set_age()
except Exception as e:
print(e)
print(f"after set_age() : {camphor.get_age()=}")
結果成功修改了age屬性的值:物件.屬性 = ???
直接賦值安全多了?註1: 假設我們不知道,或專案團隊禁止使用上一篇講的用_Tree__breed
存取私有屬性的「後門」。